-- LibreBoost, by ffoxD. Reusable content, use as long as you credit.
-- Credit to MARIOMARIO13531, and to everyone in the Discord server that helped me.
local function LibreBoost(player)
    -- Prevents the code from running in NiGHTs special stages.
	if (maptol & TOL_NIGHTS) then
		return
	end
	if player.mo.skin == "jasonfox" and player.mo.valid
		-- Lets the player boost.
		if not (player.pflags & PF_STASIS)
		and not (player.pflags & PF_FULLSTASIS)
		and not (player.pflags & PF_STARTDASH)
		and not (player.pflags & PF_FINISHED)
		and	player.playerstate ~= PST_DEAD
		and player.powers[pw_carry] == CR_NONE
		and P_IsObjectOnGround(player.mo)
		and not P_PlayerInPain(player)then
		
			if not (player.cmd.buttons & player.boostbutton)
				player.canboost = true
			end
		else
			player.canboost = false
		end
		if player.canboost == nil then
			player.canboost = true
		end
		-- Tells the game when the player shall boost, and whenever not.
		if (player.cmd.buttons & player.boostbutton)
			and player.canboost
			player.boosting = true
		else
			player.boosting = false
		end
		-- Determines how fast shall the player boost.
		player.boostspeed = 4 * player.normalspeed / 3
		-- Stores the player's speed angle.
		if player.speed > player.normalspeed then
			player.momangle2 = R_PointToAngle2(0,0,player.mo.momx,player.mo.momy)
		else
			player.momangle2 = player.mo.angle
		end
		-- What happens if the player boosts.
		if player.boosting then
			if not player.cmd.forwardmove then
				player.cmd.forwardmove = 50 --Intentionally not in PreThinkFrame
			end
			player.drawangle = player.momangle2
			player.charflags = $|SF_NOSKID|SF_RUNONWATER|SF_CANBUSTWALLS
			if player.mo.state == S_PLAY_STND
				or player.mo.state == S_PLAY_WALK
				or player.mo.state == S_PLAY_WAIT
				or player.mo.state == S_PLAY_EDGE then
				player.mo.state = S_PLAY_RUN
			end
			if player.speed < (player.boostspeed) then
				P_Thrust(player.mo, player.momangle2, player.boostspeed - player.speed)
			end
		else -- What happens if the player isn't boosting. Mostly resetting values.
			if not (skins[player.mo.skin].flags & SF_NOSKID) then
				player.charflags = $ & ~SF_NOSKID
			end
			if not (skins[player.mo.skin].flags & SF_RUNONWATER) then
				player.charflags = $ & ~SF_RUNONWATER
			end
			if not (skins[player.mo.skin].flags & SF_CANBUSTWALLS ) then
				player.charflags = $ & ~SF_CANBUSTWALLS
			end
			player.hasnomomentum = true -- Prevents XMomentum from preserving your speed.
		end
	end
end

addHook("PlayerThink", LibreBoost)

addHook("PlayerCanDamage", function(player) -- Player kills enemies while boosting
    if player.boosting then
        return true
    end
end)

addHook("MobjMoveBlocked", function(mo) -- You shall not boost if stopped by walls.
    local player = mo.player
    player.canboost = false
	player.boosting = false
end, MT_PLAYER)

addHook("MobjMoveCollide", function(mo, spike) -- Spike breaking by ARJr.
    if mo.valid
    and (mo.type == MT_PLAYER)
	and mo.player.boosting
    and spike.type == MT_SPIKE
		if (spike.z >= (mo.z - 16*FRACUNIT)) and (spike.z <= (mo.z + mo.height + 16*FRACUNIT))
			P_KillMobj(spike, mo, mo)
		elseif (spike.flags2 & MF2_OBJECTFLIP)
		and (spike.z <= (mo.z - 16*FRACUNIT)) and (spike.z >= (mo.z + mo.height+ 16*FRACUNIT))
			P_KillMobj(spike, mo, mo)
        end
    end
end)

local function LibreBoost(player) -- Super Form
    -- Prevents the code from running in NiGHTs special stages.
	if (maptol & TOL_NIGHTS) then
		return
	end
	if player.mo.skin == "jasonfox" and player.mo.valid and player.powers[pw_super] > 0
		-- Lets the player boost.
		if not (player.pflags & PF_STASIS)
		and not (player.pflags & PF_FULLSTASIS)
		and not (player.pflags & PF_STARTDASH)
		and not (player.pflags & PF_FINISHED)
		and	player.playerstate ~= PST_DEAD
		and player.powers[pw_carry] == CR_NONE
		and not P_PlayerInPain(player)then
			if not (player.cmd.buttons & player.boostbutton)
				player.canboost = true
			end
		else
			player.canboost = false
		end
		if player.canboost == nil then
			player.canboost = true
		end
		-- Tells the game when the player shall boost, and whenever not.
		if (player.cmd.buttons & player.boostbutton)
			and player.canboost
			player.boosting = true
		else
			player.boosting = false
		end
		-- Determines how fast shall the player boost.
		player.boostspeed = 7 * player.normalspeed / 3
		-- Stores the player's speed angle.
		if player.speed > player.normalspeed then
			player.momangle2 = R_PointToAngle2(0,0,player.mo.momx,player.mo.momy)
		else
			player.momangle2 = player.mo.angle
		end
		-- What happens if the player boosts.
		if player.boosting then
			if not player.cmd.forwardmove then
				player.cmd.forwardmove = 50 --Intentionally not in PreThinkFrame
			end
			player.drawangle = player.momangle2
			player.charflags = $|SF_NOSKID|SF_RUNONWATER|SF_CANBUSTWALLS
			if player.mo.state == S_PLAY_STND
				or player.mo.state == S_PLAY_WALK
				or player.mo.state == S_PLAY_WAIT
				or player.mo.state == S_PLAY_EDGE then
				player.mo.state = S_PLAY_RUN
			end
			if player.speed < (player.boostspeed) then
				P_Thrust(player.mo, player.momangle2, player.boostspeed - player.speed)
			end
		else -- What happens if the player isn't boosting. Mostly resetting values.
			if not (skins[player.mo.skin].flags & SF_NOSKID) then
				player.charflags = $ & ~SF_NOSKID
			end
			if not (skins[player.mo.skin].flags & SF_RUNONWATER) then
				player.charflags = $ & ~SF_RUNONWATER
			end
			if not (skins[player.mo.skin].flags & SF_CANBUSTWALLS ) then
				player.charflags = $ & ~SF_CANBUSTWALLS
			end
			player.hasnomomentum = true -- Prevents XMomentum from preserving your speed.
		end
	end
end